﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;

namespace Sofire.DataComm.Net
{
    /// <summary>
    /// 表示异步接收的 <see cref="System.IAsyncResult.AsyncState"/> 用户自定义数据。
    /// </summary>
    public class ReceiveStateObject : SocketStateObjectBase
    {
        /// <summary>
        /// 初始化 <see cref="Sofire.DataComm.Net.ReceiveStateObject"/> 的新实例。
        /// </summary>
        /// <param name="remoteSocket">字节数据来源的 <see cref="System.Net.Sockets.Socket"/>。</param>
        public ReceiveStateObject(Socket remoteSocket) : base(remoteSocket) { }

        private List<BufferPackage> _bufferPackageLists;

        private BufferPackage _firstPackage;

        private bool isInited = false;

        /// <summary>
        /// 指定接收到的缓冲区长度，添加缓冲区集合。
        /// </summary>
        /// <param name="length">接收到的缓冲区长度。</param>
        public void Add(int length)
        {
            var package = new BufferPackage(this.Buffer, length);
            
            //- 以下方式采用“最优效率法则”

            if(isInited)
            {
                //- 第 3 次
                this._bufferPackageLists.Add(package);
            }
            else
            {
                if(this._firstPackage == null)
                {
                    //- 第 1 次
                    this._firstPackage = package;
                }
                else
                {
                    //- 第 2 次
                    if(this._bufferPackageLists == null)
                    {
                        this._bufferPackageLists = new List<BufferPackage>(7);
                        this._bufferPackageLists.Add(this._firstPackage);
                        this._firstPackage = null;
                    }
                    this._bufferPackageLists.Add(package);
                    isInited = true;
                }
            }
        }

        /// <summary>
        /// 合并所有接收的字节数据，并重置当前自定义数据。
        /// </summary>
        /// <returns>返回合并后的字节数据。</returns>
        public byte[] MergeBytes()
        {
            isInited = false;
            byte[] bytes;
            if(this._bufferPackageLists == null)
            {
                bytes = new byte[this._firstPackage.Length];
                Array.Copy(this._firstPackage.Buffer, bytes, this._firstPackage.Length);
                this._firstPackage.Buffer = null;
                this._firstPackage = null;
                return bytes;
            }
            //    return this.ToMultiBytes();
            //    List<byte> byteList = new List<byte>(this._bufferPackageLists.Count * ReliablySocket.DefaultBufferLength);
            //    byte b = 0;
            //    foreach(var package in this._bufferPackageLists)
            //    {
            //        for(int i = 0 ; i < package.Length ; i++)
            //        {
            //            b = package.Buffer[i];
            //            byteList.Add(b);
            //        }
            //        package.Buffer = null;
            //    }
            //    _bufferPackageLists = null;
            //    if(b == 0) byteList.RemoveAt(byteList.Count - 1);
            //    return byteList.ToArray();
            //}

            //private byte[] ToMultiBytes()
            //{
            int packageCount = this._bufferPackageLists.Count;
            int lastIndex = packageCount - 1;
            var lastPackage = this._bufferPackageLists[lastIndex];
            int byteLength;
            if(lastPackage.Length == 1 && Buffer[0] == 0)
            {
                lastPackage.Buffer = null;
                packageCount--;
                byteLength = lastIndex * SocketBase.DefaultBufferLength;
            }
            else byteLength = lastIndex * SocketBase.DefaultBufferLength + lastPackage.Length;

            bytes = new byte[byteLength];

            int byteIndex = 0;
            for(int i = 0 ; i < packageCount ; i++)
            {
                lastPackage = this._bufferPackageLists[i];
                Array.Copy(lastPackage.Buffer, 0, bytes, byteIndex, lastPackage.Length);
                byteIndex += lastPackage.Length;
                lastPackage.Buffer = null;
            }
            this._bufferPackageLists.Clear();
            this._bufferPackageLists = null;
            return bytes;
        }
    }
}
